﻿using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Threading;
using Microsoft.EntityFrameworkCore;
using YZAutoDWR.Data;
using YZAutoDWR.Entity;

namespace YZAutoDWR.Handler;

public class ConfigHandler
{
    private readonly DWRDbContext _db;

    /* 延迟保存计时器 */
    private readonly DispatcherTimer _saveTimer;
    private Func<Task>? _pendingSaveAction;
    private void OnSaveTimerTick(object? sender, EventArgs e) => _ = ExecutePendingSaveAsync();
    private object? _lastValue;
    private bool _disposed;

    public ConfigHandler
        (DWRDbContext dbContext)
    {
        _db = dbContext;

        // 初始化保存计时器
        _saveTimer = new DispatcherTimer
        {
            Interval = TimeSpan.FromSeconds(1)
        };
        _saveTimer.Tick += OnSaveTimerTick;
    }

    /// <summary>
    /// 注册文本框内容自动保存, 每当用户停止输入后, 达到计时器间隔时，自动执行保存操作
    /// </summary>
    /// <param name="textBox">文本框</param>
    /// <param name="fieldName">数据库中关联的字段名</param>
    /// <param name="valueParser">数据保存前进行值转换</param>
    public void RegisterAutoSaveTextBox(TextBox textBox, string fieldName, Func<string, object>? valueParser = null)
    {
        valueParser ??= text => text; // 不需要进行值转换时直接保存输入框的原始值

        LoadInitialValueAsync(textBox, fieldName).ConfigureAwait(false);

        // 监听文本变化, 每次值变化时触发保存请求
        textBox.TextChanged += (_, _) =>
        {
            try
            {
                var value = valueParser(textBox.Text);
                RequestSave(value, () => SaveFieldAsync(fieldName, value));
            }
            catch (Exception ex)
            {
                Console.WriteLine($"文本框内容解析异常: {ex.Message}");
            }
        };
    }

    /// <summary>
    /// 文本框保存请求, 文本框的内容变动时会反复触发保存请求, 但只要没到定时器约定的时间则不会实际保存内容
    /// </summary>
    /// <param name="newValue">文本框中实时输入的值</param>
    /// <param name="saveAction">用于保存的逻辑</param>
    private void RequestSave(object newValue, Func<Task>? saveAction)
    {
        if (Equals(newValue, _lastValue)) return;

        _saveTimer.Stop();
        _pendingSaveAction = saveAction;
        _lastValue = newValue;
        _saveTimer.Start();
    }

    /// <summary>
    /// 执行文本框内容保存
    /// </summary>
    private async Task ExecutePendingSaveAsync()
    {
        _saveTimer.Stop();

        var saveAction = _pendingSaveAction;
        _pendingSaveAction = null;

        if (saveAction == null) return;

        try
        {
            await saveAction.Invoke();
            Console.WriteLine("配置已自动保存");
        }
        catch (Exception ex) when (ex is not OperationCanceledException)
        {
            Console.WriteLine($"自动保存失败: {ex.GetType().Name} - {ex.Message}");
        }
    }

    /// <summary>
    /// 文本框内容保存至数据库
    /// </summary>
    /// <param name="fieldName">数据库字段名</param>
    /// <param name="value">要保存的值</param>
    private async Task SaveFieldAsync(string fieldName, object value)
    {
        try
        {
            var existingConfig = await _db.UserConfig
                .FirstOrDefaultAsync(x => x.Id == 1);

            if (existingConfig == null)
            {
                var newConfig = new UserConfigEntity { Id = 1 };
                _db.Entry(newConfig).Property(fieldName).CurrentValue = value;
                _db.UserConfig.Add(newConfig);
            }
            else
            {
                _db.Entry(existingConfig).Property(fieldName).CurrentValue = value;
                _db.UserConfig.Update(existingConfig);
            }

            await _db.SaveChangesAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"保存配置异常: {ex.Message}");
        }
    }

    /// <summary>
    /// 加载已有的配置内容到文本框
    /// </summary>
    /// <param name="textBox">文本框</param>
    /// <param name="fieldName">数据库中关联的字段名</param>
    private async Task LoadInitialValueAsync(TextBox textBox, string fieldName)
    {
        try
        {
            var query = _db.UserConfig.Where(x => x.Id == 1)
                .Select(x => EF.Property<string>(x, fieldName))
                .FirstOrDefaultAsync();
            var value = await query;

            textBox.Dispatcher.Invoke(() => textBox.Text = value ?? string.Empty);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"加载用户配置异常: {ex.Message}");
        }
    }

    public void Dispose()
    {
        if (_disposed) return;

        _saveTimer.Stop();
        _saveTimer.Tick -= OnSaveTimerTick;
        _disposed = true;
    }
}